package com.naiterui.ehp.bs.pharmacist.interceptor;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.support.exception.PublicService;
import com.naiterui.ehp.bp.support.security.HeaderConstant;
import com.naiterui.ehp.bp.support.security.SettingConfig;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.context.SpringContextHolder;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.pharmacist.entity.Pharmacist;
import com.naiterui.ehp.bs.pharmacist.exception.ExceptionCodes;
import com.naiterui.ehp.bs.pharmacist.repository.mysql.PharmacistRepository;
import com.naiterui.ehp.bs.pharmacist.utils.Constants;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author guoyongxiang
 * @date 2019-06-22 13:05
 * @since 1.0.0
 */
public class PasswordExpireInterceptor implements HandlerInterceptor {

    private static final Logger LOGGER = LoggerFactory.getLogger(PasswordExpireInterceptor.class);

    private static final int RDS_KEY_LAST_MODIFY_EXPIRE = 10 * 60;

    private static String[] NOCHECK_URI = {
            // 客户端升级&升级配置JSP
            "/pharmacist/checkVersion",
            "/pharmacist/saveVersion",
            "/pharmacist/saveH5Version",

            // 登录 & 注册 & 获取短信验证码
            "/pharmacist/login",
            "/pharmacist/login/*",
            "/pharmacist/sendSms",
            "/pharmacist/time.jsp",

            // 获取首页启动图信息
            "/index/startInfo",

            // H5分享二维码
            "/auth/getAppSpreadInfo",

            // B2C使用
            "/api/recdrug/usage",

            // 客户端基础配置
            "/doctorInfo/doctorConfig",
            "/doctorInfo/globalConfig",
            "/index/noticeDetail",

            // 客户端活动页JS
            "/medication/salePrice"
    };

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // ************************************Header 参数获取**************************************
        // 平台
        String platform = request.getHeader(HeaderConstant.HEADER_PLATFORM);
        // 来源
        String origin = request.getHeader(HeaderConstant.HEADER_ORIGIN);

        String inner = request.getHeader(SettingConfig.HEADER_INNER);
        //只拦截药师app的请求， 内部请求直接放行
        if (!(HeaderConstant.HEADER_INNER_REQUEST_YES + "").equals(inner)) {
            // URL
            String url = request.getServletPath();
            String pharmacistId = request.getParameter(SettingConfig.PHARMACIST_ID);
            Integer focreModifyDay = ConfigUtil.getInt("pharmacist.password.modify.force.day");

            //        // 仅校验医生端
            //        if (!(HeaderConstant.HEADER_ORIGIN_DOCTOR_APP + "").equals(origin) || focreModifyDay == null || focreModifyDay == 0) {
            //            return true;
            //        }
            // 校验药师ID
            if (!StringUtils.isNumeric(pharmacistId) || checkVersionIgnoreUrl(url)) {
                return true;
            }
            // 校验密码过期
            Date lastModify = this.getLastPasswordModify(response, Long.valueOf(pharmacistId));
            if (lastModify == null) {
                this.stuffErrorCode(response, ExceptionCodes.USER_NOT_EXIST);
                return false;
            }
            Date expireDate = DateUtil.addDays(lastModify, focreModifyDay);
            if (System.currentTimeMillis() > expireDate.getTime()) {
                this.stuffErrorCode(response, ExceptionCodes.PWD_EXPIRE_ERROR);
                return false;
            }
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

    }

    /**
     * 校验免校验列表
     * LoginInterceptor.checkVersionIgnoreUrl()
     *
     * @param reqUrl
     *
     * @return
     *
     * @Author guoyongxiang
     * @Date 2017年6月28日
     * @since 2.8.0
     */
    private static boolean checkVersionIgnoreUrl(String reqUrl) {
        for (String uri : NOCHECK_URI) {
            if (matchUrl(uri, reqUrl)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 匹配URL
     * LoginInterceptor.matchUrl()
     *
     * @param matchUrl 匹配规则(左匹配支持*)
     * @param reqUrl   被检测URL
     *
     * @return
     *
     * @Author guoyongxiang
     * @Date 2017年6月28日
     * @since 2.8.0
     */
    private static boolean matchUrl(String matchUrl, String reqUrl) {
        Pattern pattern = Pattern.compile(matchUrl);
        Matcher matcher = pattern.matcher(reqUrl);
        return matcher.lookingAt();
    }

    private Date getLastPasswordModify(HttpServletResponse response, Long pharmacistId) {
        Date doctorLastModify = (Date) RedisUtil.valueOps().getObject(Constants.RDS_KEY_LAST_MODIFY + pharmacistId);
        if (doctorLastModify == null) {
            PharmacistRepository loginDao = SpringContextHolder.getBean("pharmacistRepository", PharmacistRepository.class);
            Pharmacist pharmacist = loginDao.get(pharmacistId);
            if (pharmacist == null) {
                LOGGER.warn("药师ID不存在 pharmacistId:{}", pharmacistId);
                return null;
            }
            if (pharmacist.getLastPwdModify() != null) {
                setDoctorLastPasswordModifyCache(pharmacistId, pharmacist.getLastPwdModify());
                doctorLastModify = pharmacist.getLastPwdModify();
            }
        }
        return doctorLastModify;
    }

    /**
     * 设置改密缓存
     *
     * @param doctorId
     * @param modifyTime
     */
    public static void setDoctorLastPasswordModifyCache(Long doctorId, Date modifyTime) {
        RedisUtil.valueOps().setObject(Constants.RDS_KEY_LAST_MODIFY + doctorId, modifyTime, RDS_KEY_LAST_MODIFY_EXPIRE);
    }

    /**
     * SecurityServiceImpl.stuffErrorCode()
     *
     * @param response
     * @param errorCode
     *
     * @throws IOException
     * @Author mudou
     * @Date 2017年7月10日
     * @since 2.8.0
     */
    private void stuffErrorCode(HttpServletResponse response, int errorCode) throws IOException {
        if (null == response) {
            return;
        }
        response.getWriter().println(JsonMapper.toJson(PublicService.returnResponseVO(errorCode)));
    }

}
